package com.logistics.organization.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.logistics.account.service.AccountService;
import com.logistics.dictionary.entity.model.DictionaryRow;
import com.logistics.menu.entity.domain.Menu;
import com.logistics.organization.entity.domain.Organization;
import com.logistics.organization.entity.model.OrganizationSave;
import com.logistics.organization.entity.model.OrganizationPager;
import com.logistics.organization.entity.model.OrganizationRow;
import com.logistics.organization.mapper.OrganizationMapper;
import com.logistics.sequence.service.SequenceService;
import com.logistics.utils.aspect.annotation.Insert;
import com.logistics.utils.aspect.annotation.Pager;
import com.logistics.utils.bean.ResultPager;
import com.logistics.utils.constants.Dictionary;
import com.logistics.utils.constants.Message;
import com.logistics.utils.exception.MessageException;
import com.logistics.utils.message.Manager;
import com.logistics.utils.tool.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;

@Service
public class OrganizationService extends ServiceImpl<OrganizationMapper, Organization> {

    @Autowired
    private SequenceService sequenceService;

    @Autowired
    @Lazy
    private AccountService accountService;

    /**
     * 分页查询数据
     * @param param
     * @return
     */
    @Pager
    public ResultPager<OrganizationRow> pager(OrganizationPager param){
        IPage page = new Page(param.getCurrent(), param.getPageSize());
        QueryWrapper<Organization> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Organization::getParentId, 1);
        if(StringUtils.isNotNull(param.getName())){
            queryWrapper.lambda().like(Organization::getName, param.getName());
        }
        if(StringUtils.isNotNull(param.getCode())){
            queryWrapper.lambda().like(Organization::getCode, param.getCode());
        }
        if(StringUtils.isNotNull(param.getType())){
            queryWrapper.lambda().eq(Organization::getType, param.getType());
        }
        IPage<Organization> result = this.page(page, queryWrapper.lambda().orderByDesc(Organization::getCreateTime));
        return new ResultPager(dataFormatter(result.getRecords()), (int) result.getTotal());
    }

    /**
     * 根据id查询编码
     * @param ids
     * @return
     */
    public String codeById(String... ids) throws MessageException {
        if(StringUtils.isNull(ids)){
            throw new MessageException(Manager.getMessage(Message.MSG1005.getCode()));
        }
        List<Organization> result = this.list(new LambdaQueryWrapper<Organization>().in(Organization::getId, ids));
        return result.stream().map(e -> e.getCode()).collect(Collectors.joining());
    }

    /**
     * 查找树形
     * @return
     */
    public List<OrganizationRow> listTree(){
        List<Organization> list = this.list(new LambdaQueryWrapper<Organization>()
                .ne(Organization::getParentId, 0).
                orderByDesc(Organization::getCreateTime));
        if(StringUtils.isNull(list)){
            return null;
        }
        List<OrganizationRow> rows = list.stream().map(e -> OrganizationRow.build(e))
                .collect(Collectors.toList());
        return rows.stream().filter(e -> e.getParentId() == 1).map(e -> {
            e.setChildren(getChildren(e, rows));
            return e;
        }).collect(Collectors.toList());
    }

    /**
     * 查找详细
     * @param id
     * @return
     * @throws MessageException
     */
    public OrganizationRow detail(String id) throws MessageException {
        if(StringUtils.isNull(id)){
            throw new MessageException(Manager.getMessage(Message.MSG1005.getCode()));
        }
        Organization organization = this.getOne(new LambdaQueryWrapper<Organization>()
                .eq(Organization::getId, Integer.parseInt(id)));
        return OrganizationRow.build(organization);
    }

    /**
     * 添加
     */
    @Insert
    @Transactional
    public void save(OrganizationSave save){
        List<Organization> list = this.list();
        if(StringUtils.isNull(save.getId())){
            String code = getCode(save.getType());
            UnaryOperator<String> insert = s -> s + code;
            save.setCode(getCode(save.getParentId(), list, insert));
            this.save(Organization.build(save));
        }else {
            this.update(Organization.build(save),
                    new LambdaQueryWrapper<Organization>().eq(Organization::getId, save.getId()));
        }
    }

    /**
     * 删除
     * @param ids
     * @throws MessageException
     */
    public void delete(String ids) throws MessageException {
        if(StringUtils.isNull(ids)){
            throw new MessageException(Manager.getMessage(Message.MSG1005.getCode()));
        }
        List<String> removeIds = getRemoveIds(ids);
        accountService.checkOrganization(removeIds);
        this.remove(new LambdaQueryWrapper<Organization>().in(Organization::getId,
                removeIds));
    }

    /**
     * 根据ID查询班组编码
     * @param id
     */
    public String wcCodeById(String id){
        Organization row = this.getOne(new LambdaQueryWrapper<Organization>().eq(Organization::getId, id));
        return row.getWcCode();
    }

    /**
     *  获取节点下所有ID
     * @param ids
     * @return
     */
    private List<String> getRemoveIds(String ids){
        List<String> removeId = StringUtils.splitToList(ids , ",");
        List<String> idList = this.list(new LambdaQueryWrapper<Organization>().in(Organization::getParentId, removeId)).
                stream().map(e -> e.getId().toString()).collect(Collectors.toList());
        if(idList.size() > 0)
            removeId.addAll(getRemoveIds(StringUtils.listToString(idList, ",")));
        return removeId;
    }

    /**
     * 查找子集
     * @param root
     * @param allList
     * @return
     */
    private List<OrganizationRow> getChildren(OrganizationRow root, List<OrganizationRow> allList){
        return allList.stream().filter(e -> e.getParentId() == root.getId()).map(e ->{
            e.setChildren(getChildren(e, allList));
            return e;
        }).collect(Collectors.toList());
    }

    /**
     * 获取编码
     * @param type
     * @return
     */
    private String getCode(String type){
        if(Dictionary.ORGANIZATION.getCode().equals(type)){
            return sequenceService.getCode(Dictionary.ORGANIZATION.getName(), 3);
        }else if(Dictionary.DEPARTMENT.getCode().equals(type)){
            return sequenceService.getCode(Dictionary.DEPARTMENT.getName(), 2);
        }else if(Dictionary.POST.getCode().equals(type)){
            return sequenceService.getCode(Dictionary.DEPARTMENT.getName(), 3);
        }
        return null;
    }

    /**
     * 获取编码
     * @param parentId
     * @param list
     * @param insert
     * @return
     */
    private String getCode(Integer parentId, List<Organization> list,
                           UnaryOperator<String> insert){
        String code = list.stream().filter(e -> e.getId() == parentId).map(e -> {
            getCode(e.getParentId(), list, insert);
            return e.getCode();
        }).collect(Collectors.joining(""));
        return insert.apply(code);
    }

    /**
     * 数据转换
     * @param rows
     * @return
     */
    private List<OrganizationRow> dataFormatter(List<Organization> rows){
//        List<Integer> ids = rows.stream().map(e -> e.getId()).collect(Collectors.toList());
        List<Organization> allList = this.list();
        return rows.stream().map(OrganizationRow::build)
                .map(e -> {
                    e.setChildren(getChildren(e, allList.stream().map(s -> OrganizationRow.build(s)).collect(Collectors.toList())));
                    return e;
                }).collect(Collectors.toList());
    }

}
